iT邦幫忙

2026 iThome 鐵人賽

DAY 6
0
Software Development

文科生的軟體工程啟蒙:用一個代購 App,看懂 30 個系統設計觀念系列 第 6

記憶體中的資料組織——Array vs. Object 在資料查詢與更新上的工程權衡

  • 分享至 

  • xImage
  •  

昨天我們談的是 API 怎麼定義前後端之間的合約——資料怎麼包裝、怎麼送、送到之後狀態碼代表什麼意思。但那份合約只解決了「資料怎麼安全地從後端搬到前端」,沒有回答下一個問題:資料到了前端瀏覽器的記憶體裡之後,要用什麼樣的容器裝著它?如果選錯容器,就算 API 設計得再嚴謹,前端還是會處理得又亂又慢。這篇要比較兩種最基礎的容器——陣列(Array)與物件(Object)——在代購 App 的資料查詢與更新上,各自的工程權衡,也是這個系列第一次真的要碰程式碼的地方。

一、資料結構特性比較

陣列 Array

定義:在記憶體中依序排列的一系列元素。

優勢:透過索引存取速度極快,且天生維護資料的插入順序。

劣勢:若需在開頭或中間插入、刪除元素,需搬移後續所有資料;依值搜尋時需線性掃描整個陣列。

物件 Object / Hash Table

定義:透過鍵映射到對應的值,概念上接近雜湊表的行為。

優勢:不論資料量多大,透過鍵查詢與更新的效能都趨近於常數時間 O(1)。

劣勢:記憶體開銷較大。另外要澄清一個常見的過時說法——JavaScript 物件自 ES2015 起,屬性順序其實是有規範保證的:字串鍵依插入順序排列,整數型的鍵則會排到最前面並依數字大小排序。「物件沒有順序保證」是 ES5 以前的舊觀念了。不過如果需要更嚴謹、且 key 可以是任意型別的有序鍵值結構,JavaScript 提供了專門的 Map,比物件更適合這種用途。

二、操作時間複雜度分析

  • 陣列查詢:索引查詢為 O(1),但若依屬性搜尋則為 O(n)。
  • 陣列更新:修改特定索引為 O(1);在尾端新增或刪除也是 O(1);但在開頭或中間插入、刪除,因為要搬移後面所有元素,是 O(n)。
  • 物件查詢:透過 Key 直接定位,為 O(1)。
  • 物件更新:同樣透過 Key 直接定位並覆寫,為 O(1)。

三、代購 App 案例:如果只有陣列,或只有物件,會發生什麼事

情境:代購 App 要同時做到兩件事——依照建立時間把所有訂單依序列出來,以及買家點擊某一筆訂單時,能即時更新它的狀態。

如果只用陣列

const orders = [
  { id: 'o1', status: '待採購' },
  { id: 'o2', status: '採購中' },
  { id: 'o3', status: '已送達' }
];

// 買家要把 o2 改成「已購入」,得先找到它
const target = orders.find(order => order.id === 'o2');
target.status = '已購入';
// find() 要一筆一筆比對 id,訂單越多,這行越慢——O(n)

訂單資料一筆一筆放進陣列,天生就有順序,很適合直接拿去渲染列表。但訂單只有三筆感覺不出差別,訂單一多,每一次更新都要重新掃過整份清單,App 會越用越卡。

如果只用物件

const ordersById = {
  o1: { id: 'o1', status: '待採購' },
  o2: { id: 'o2', status: '採購中' },
  o3: { id: 'o3', status: '已送達' }
};

// 直接用 key 存取,不用找
ordersById.o2.status = '已購入';
// 不管有幾筆訂單,這行永遠一樣快——O(1)

更新變快了,但物件不保證這件事:你沒辦法可靠地說「第一筆」訂單是哪一個,如果要照建立時間排序顯示,物件本身幫不上忙。

兩個問題剛好互補,所以實務上工程師會把兩者結合:保留一個物件負責快速查找與更新,另外維護一個陣列只負責記錄顯示順序。這種做法在業界有個固定的名字,叫 normalized state(Redux 官方文件就是這樣教的),常見形狀是同時有一個 byId 物件跟一個 allIds 陣列。

四、結論

工程決策沒有絕對的最優,只有最適合場景的選擇。陣列適合需要維護順序與遍歷的資料集,物件則是處理快速查找與狀態更新的利器。代購 App 這個例子剛好把兩者的缺口都暴露出來:少了陣列,順序會亂;少了物件,查找會慢。把兩者結合成 normalized state,是實務上很常見、也很值得記住的模式。陣列跟物件一直到現在對我來說都像是兩個各自獨立的名詞,背不起來也搞不懂為什麼要學——因為「記憶體」這件事本身對我來說是完全空白的概念,我沒辦法想像前端、後端的程式碼,怎麼會跟電腦裡資料怎麼排放這種底層的事情扯上關係。後來讓我想通的方法是反過來想:假設今天沒有陣列,訂單清單會亂七八糟、沒有固定順序;假設今天沒有物件,每次要更新一筆訂單都得把整份清單從頭找一遍,訂單一多整個 App 就會變得又亂又慢。用「少了它會有多災難」這個角度去想,比直接想「它是什麼」更容易讓我抓住重點。


上一篇
Day 5:介面合約設計——RESTful 原則、API 規格定義與資料交換協議
系列文
文科生的軟體工程啟蒙:用一個代購 App,看懂 30 個系統設計觀念6
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言